﻿using Swifter.Reflection;
using Swifter.RW;
using System;
using System.Collections.Generic;

namespace SwifterJson
{
    public class GenericInterface<T> : IValueInterface<T>
    {
        public T ReadValue(IValueReader valueReader)
        {
            var rw = new GenericRW<T>();

            valueReader.ReadObject(rw);

            return (T)rw.Content;
        }

        public void WriteValue(IValueWriter valueWriter, T value)
        {
            if (typeof(T).IsValueType || typeof(T).IsSealed || value.GetType() == typeof(T))
            {
                var rw = new GenericRW<T>();

                rw.Content = value;

                valueWriter.WriteObject(rw);
            }
            else
            {
                ValueInterface.GetInterface(value).Write(valueWriter, value);
            }
        }
    }

    public class GenericInterfaceMaper : IValueInterfaceMaper
    {
        public IValueInterface<T> TryMap<T>()
        {
            if (typeof(T).IsAbstract || typeof(T).IsInterface || typeof(T) == typeof(object))
            {
                return new GenericInterface<T>();
            }

            return null;
        }
    }

    public class GenericRW<T> : IDataRW<string>
    {
        const string TypeName = "typeName";

        XObjectRW internalObjectRW;

        public GenericRW()
        {
            internalObjectRW = XObjectRW.Create<T>();
        }

        public IValueRW this[string key] {
            get {
                if (key == TypeName)
                {
                    return new ValueCopyer<string>(this, TypeName);
                }

                return internalObjectRW[key];
            }
        }

        IValueReader IDataReader<string>.this[string key] => this[key];

        IValueWriter IDataWriter<string>.this[string key] => this[key];

        public IEnumerable<string> Keys {
            get {
                yield return TypeName;

                foreach (var item in internalObjectRW.Keys)
                {
                    yield return item;
                }
            }
        }

        public int Count => internalObjectRW.Count + 1;

        public Type ContentType => internalObjectRW.ContentType;

        public object Content {
            get => internalObjectRW.Content;
            set => internalObjectRW.Content = value;
        }

        public void Initialize()
        {
        }

        public void Initialize(int capacity)
        {
        }

        public void OnReadAll(IDataWriter<string> dataWriter)
        {
            dataWriter[TypeName].WriteString(typeof(T).FullName);

            internalObjectRW.OnReadAll(dataWriter);
        }

        public void OnReadValue(string key, IValueWriter valueWriter)
        {
            // TODO: 这个方法没有在 Swifter.Json 中使用。
            throw new NotImplementedException();
        }

        public void OnWriteAll(IDataReader<string> dataReader)
        {
            // TODO: 这个方法没有在 Swifter.Json 中使用。
            throw new NotImplementedException();
        }

        public void OnWriteValue(string key, IValueReader valueReader)
        {
            if (key == TypeName)
            {
                var typeName = ValueInterface<string>.ReadValue(valueReader);

                var type = typeof(T).Assembly.GetType(typeName);

                internalObjectRW = XObjectRW.Create(type);

                internalObjectRW.Initialize();
            }
            else
            {
                internalObjectRW.OnWriteValue(key, valueReader);
            }
        }
    }

}
